/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
 * Copyright (c) 2014 Magister Solutions
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation;
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Author: Frans Laakso <frans.laakso@magister.fi>
 *
 */

#include "ns3/applications-module.h"
#include "ns3/core-module.h"
#include "ns3/internet-module.h"
#include "ns3/network-module.h"
#include "ns3/satellite-module.h"
#include "ns3/traffic-module.h"

using namespace ns3;

/**
 * \file sat-random-access-dynamic-load-control-example.cc
 * \ingroup satellite
 *
 * \brief  This is an example of Random Access usage in satellite network. This
 *         example uses RA models based on DVB-RCS2 specification. CRA
 *         is disabled in this example. The example allows to set various
 *         RA parameters such as the maximum rate limitation related
 *         parameters, back off and load control related parameters.
 *
 *         By default, the RA dynamic load control is enabled in this
 *         example and the example is modified to produce higher load compared
 *         to the basic random access example. As defined in specification,
 *         the operation mode between Slotted ALOHA and CRDSA is determined
 *         by the number of instances parameter.
 *
 *         The script is using CBR application in user defined scenario,
 *         which means that user can change the scenario size quite to be
 *         whatever between 1 and full scenario (72 beams). Currently it
 *         is configured to using only one beam. CBR application is sending
 *         packets in RTN link, i.e. from UT side to GW side. Packet trace
 *         is enabled by default. End user may change the number of UTs and
 *         end users from the command line.
 *
 *         execute command -> ./waf --run "sat-random-access-dynamic-load-control-example
 * --PrintHelp"
 */

NS_LOG_COMPONENT_DEFINE("sat-random-access-dynamic-load-control-example");

int
main(int argc, char* argv[])
{
    uint32_t beamId(1);
    uint32_t endUsersPerUt(1);
    uint32_t utsPerBeam(30);
    uint32_t packetSize(20);
    Time interval(Seconds(0.01));
    Time simLength(Seconds(5.00));
    Time appStartTime = Seconds(0.01);

    // Enable info logs
    LogComponentEnable("sat-random-access-dynamic-load-control-example", LOG_LEVEL_INFO);
    // LogComponentEnable ("SatRandomAccess", LOG_LEVEL_INFO);
    // LogComponentEnable ("SatUtMac", LOG_LEVEL_INFO);
    LogComponentEnable("SatPhyRxCarrier", LOG_LEVEL_INFO);
    // LogComponentEnable ("SatInterference", LOG_LEVEL_INFO);
    LogComponentEnable("SatNcc", LOG_LEVEL_INFO);
    // LogComponentEnable ("SatBeamScheduler", LOG_LEVEL_INFO);

    auto simulationHelper =
        CreateObject<SimulationHelper>("example-random-access-dynamic-load-control");
    Config::SetDefault("ns3::SatHelper::PacketTraceEnabled", BooleanValue(true));

    // Read command line parameters given by user
    CommandLine cmd;
    cmd.AddValue("endUsersPerUt", "Number of end users per UT", endUsersPerUt);
    cmd.AddValue("utsPerBeam", "Number of UTs per spot-beam", utsPerBeam);
    simulationHelper->AddDefaultUiArguments(cmd);
    cmd.Parse(argc, argv);

    // Configure error model
    SatPhyRxCarrierConf::ErrorModel em(SatPhyRxCarrierConf::EM_AVI);
    Config::SetDefault("ns3::SatUtHelper::FwdLinkErrorModel", EnumValue(em));
    Config::SetDefault("ns3::SatGwHelper::RtnLinkErrorModel", EnumValue(em));
    // Config::SetDefault ("ns3::SatUtMac::CrUpdatePeriod", TimeValue(Seconds(10.0)));

    // Disable CRA and DA
    Config::SetDefault("ns3::SatLowerLayerServiceConf::DaService0_ConstantAssignmentProvided",
                       BooleanValue(false));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::DaService1_ConstantAssignmentProvided",
                       BooleanValue(false));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::DaService2_ConstantAssignmentProvided",
                       BooleanValue(false));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::DaService3_ConstantAssignmentProvided",
                       BooleanValue(false));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::DaService0_RbdcAllowed",
                       BooleanValue(false));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::DaService1_RbdcAllowed",
                       BooleanValue(false));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::DaService2_RbdcAllowed",
                       BooleanValue(false));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::DaService3_RbdcAllowed",
                       BooleanValue(false));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::DaService0_VolumeAllowed",
                       BooleanValue(false));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::DaService1_VolumeAllowed",
                       BooleanValue(false));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::DaService2_VolumeAllowed",
                       BooleanValue(false));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::DaService3_VolumeAllowed",
                       BooleanValue(false));

    // Enable Random Access with CRDSA
    Config::SetDefault("ns3::SatBeamHelper::RandomAccessModel",
                       EnumValue(SatEnums::RA_MODEL_RCS2_SPECIFICATION));

    // Set Random Access interference model
    Config::SetDefault("ns3::SatBeamHelper::RaInterferenceModel",
                       EnumValue(SatPhyRxCarrierConf::IF_PER_PACKET));

    // Set Random Access collision model
    Config::SetDefault("ns3::SatBeamHelper::RaCollisionModel",
                       EnumValue(SatPhyRxCarrierConf::RA_COLLISION_CHECK_AGAINST_SINR));

    // Disable periodic control slots
    Config::SetDefault("ns3::SatBeamScheduler::ControlSlotsEnabled", BooleanValue(false));

    // Set dynamic load control parameters
    Config::SetDefault("ns3::SatPhyRxCarrierConf::EnableRandomAccessDynamicLoadControl",
                       BooleanValue(true));
    Config::SetDefault(
        "ns3::SatPhyRxCarrierConf::RandomAccessAverageNormalizedOfferedLoadMeasurementWindowSize",
        UintegerValue(10));

    // Set random access parameters
    Config::SetDefault("ns3::SatLowerLayerServiceConf::RaService0_MaximumUniquePayloadPerBlock",
                       UintegerValue(3));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::RaService0_MaximumConsecutiveBlockAccessed",
                       UintegerValue(6));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::RaService0_MinimumIdleBlock",
                       UintegerValue(2));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::RaService0_BackOffTimeInMilliSeconds",
                       UintegerValue(250));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::RaService0_BackOffProbability",
                       UintegerValue(1));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::RaService0_HighLoadBackOffProbability",
                       UintegerValue(1));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::RaService0_NumberOfInstances",
                       UintegerValue(3));
    Config::SetDefault(
        "ns3::SatLowerLayerServiceConf::RaService0_AverageNormalizedOfferedLoadThreshold",
        DoubleValue(0.5));
    Config::SetDefault("ns3::SatLowerLayerServiceConf::DefaultControlRandomizationInterval",
                       TimeValue(MilliSeconds(100)));
    Config::SetDefault("ns3::SatRandomAccessConf::CrdsaSignalingOverheadInBytes", UintegerValue(5));
    Config::SetDefault("ns3::SatRandomAccessConf::SlottedAlohaSignalingOverheadInBytes",
                       UintegerValue(3));

    // Creating the reference system.
    simulationHelper->SetSimulationTime(simLength);
    simulationHelper->SetUserCountPerUt(endUsersPerUt);
    simulationHelper->SetUtCountPerBeam(utsPerBeam);
    simulationHelper->SetBeamSet({beamId});

    simulationHelper->LoadScenario("geo-33E");

    simulationHelper->CreateSatScenario();

    simulationHelper->GetTrafficHelper()->AddCbrTraffic(
        SatTrafficHelper::RTN_LINK,
        SatTrafficHelper::UDP,
        interval,
        packetSize,
        NodeContainer(Singleton<SatTopology>::Get()->GetGwUserNode(0)),
        Singleton<SatTopology>::Get()->GetUtUserNodes(),
        appStartTime,
        simLength + Seconds(1),
        Seconds(0.05));

    NS_LOG_INFO("--- Cbr-user-defined-example ---");
    NS_LOG_INFO("  Packet size in bytes: " << packetSize);
    NS_LOG_INFO("  Packet sending interval: " << interval.GetSeconds());
    NS_LOG_INFO("  Simulation length: " << simLength.GetSeconds());
    NS_LOG_INFO("  Number of UTs: " << utsPerBeam);
    NS_LOG_INFO("  Number of end users per UT: " << endUsersPerUt);
    NS_LOG_INFO("  ");

    simulationHelper->RunSimulation();

    return 0;
}
